package com.boruan.shengtangfeng.core.utils;

import java.math.BigDecimal;

/**
 *
 * @author liuguangqiang
 * @date 2016年7月11日 上午9:01:15 ROUND_CEILING 如果 BigDecimal 是正的，则做 ROUND_UP
 *       操作；如果为负，则做 ROUND_DOWN 操作。 ROUND_DOWN 从不在舍弃(即截断)的小数之前增加数字。 ROUND_FLOOR
 *       如果 BigDecimal 为正，则作 ROUND_UP ；如果为负，则作 ROUND_DOWN 。 ROUND_HALF_DOWN
 *       若舍弃部分> .5，则作 ROUND_UP；否则，作 ROUND_DOWN 。 ROUND_HALF_EVEN
 *       如果舍弃部分左边的数字为奇数，则作 ROUND_HALF_UP ；如果它为偶数，则作 ROUND_HALF_DOWN 。
 *       ROUND_HALF_UP 若舍弃部分>=.5，则作 ROUND_UP ；否则，作 ROUND_DOWN 。
 *       ROUND_UNNECESSARY 该“伪舍入模式”实际是指明所要求的操作必须是精确的，，因此不需要舍入操作。 ROUND_UP 总是在非 0
 *       舍弃小数(即截断)之前增加数字。
 */
public class NumberUtils {

	/**
	 * 由于Java的简单类型不能够精确的对浮点数进行运算，这个工具类提供精 确的浮点数运算，包括加减乘除和四舍五入。
	 */
	// 默认除法运算精度
	private static final int DEF_DIV_SCALE = 3;

	private static String[] units = { "", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千", "万亿" };
	private static char[] numArray = { '零', '一', '二', '三', '四', '五', '六', '七', '八', '九' };
	// 这个类不能实例化
	private NumberUtils() {
	}


	/**
	 * int 转 中文数字
	 * 支持到int最大值
	 *
	 * @param num 要转换的整型数
	 * @return 中文数字
	 */
	public static String int2chineseNum(int num) {
		char[] val = String.valueOf(num).toCharArray();
		int len = val.length;
		StringBuilder sb = new StringBuilder();
		title:
		for (int i = 0; i < len; i++) {
			String m = val[i] + "";
			int n = Integer.valueOf(m);
			boolean isZero = n == 0;
			String unit = units[(len - 1) - i];
			if (isZero) {
				boolean falg=false;
				for(int j=i;j<len;j++){
					String a = val[j] + "";
					int b = Integer.valueOf(a);
					if(b!=0){
						falg=true;
					}
				}
				if(falg){
					if ('0' == val[i - 1]) {
						continue;
					}else {
						if(((len - 1) - i)%4==0) {
							sb.append(unit);
						}
						sb.append(numArray[n]);
					}
				}else {
					if(((len - 1) - i)%4==0){
						sb.append(unit);
						break title;
					}
				}
			} else {
				sb.append(numArray[n]);
				sb.append(unit);

			}
		}
		return sb.toString();
	}

	/**
	 * 提供精确的加法运算。
	 *
	 * @param v1
	 *            被加数
	 * @param v2
	 *            加数
	 * @return 两个参数的和
	 */
	public static double add(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.add(b2).doubleValue();
	}
	/**
	 * 提供精确的加法运算。
	 *
	 * @param v1
	 *            被加数
	 * @param v2
	 *            加数
	 * @return 两个参数的和
	 */
	public static String add(String v1, String v2) {
        if (v1==null) {
            v1="0.0";
        }
        if (v2==null) {
            v2="0.0";
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).toPlainString();
    }

	/**
	 * 提供精确的减法运算。
	 *
	 * @param v1
	 *            被减数
	 * @param v2
	 *            减数
	 * @return 两个参数的差
	 */
	public static double sub(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.subtract(b2).doubleValue();
	}
	/**
	 * 提供精确的减法运算。
	 *
	 * @param v1
	 *            被减数
	 * @param v2
	 *            减数
	 * @return 两个参数的差
	 */
	public static String sub(String v1, String v2) {
	    if (v1==null) {
	        v1="0.0";
	    }
	    if (v2==null) {
	        v2="0.0";
	    }
	    BigDecimal b1 = new BigDecimal(v1);
	    BigDecimal b2 = new BigDecimal(v2);
	    return b1.subtract(b2).toPlainString();
	}

	/**
	 * 提供精确的乘法运算。
	 *
	 * @param v1
	 *            被乘数
	 * @param v2
	 *            乘数
	 * @return 两个参数的积
	 */
	public static double mul(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.multiply(b2).doubleValue();
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后10位，以后的数字只舍不入。
	 *
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @return 两个参数的商
	 */
	public static double divDown(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		return divDown(v1, v2, DEF_DIV_SCALE);
	}

	/**
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字只舍不入。
	 *
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @param scale
	 *            表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static double divDown(Double v1, Double v2, int scale) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.divide(b2, scale, BigDecimal.ROUND_DOWN).doubleValue();
	}

	/**
	 * 提供精确的小数位只舍不入处理。
	 *
	 * @param v
	 *            需要只舍不入的数字
	 * @param scale
	 *            小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double roundDown(Double v, int scale) {
		if (v==null) {
			v=0.0D;
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_DOWN).doubleValue();
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后10位，以后的数字四舍五入。
	 *
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @return 两个参数的商
	 */
	public static double div(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		return div(v1, v2, DEF_DIV_SCALE);
	}

	/**
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
	 *
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @param scale
	 *            表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static double div(Double v1, Double v2, int scale) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	/**
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
	 *
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @param scale
	 *            表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static double div(String v1, String v2, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 提供精确的小数位四舍五入处理。
	 *
	 * @param v
	 *            需要四舍五入的数字
	 * @param scale
	 *            小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round(Double v, int scale) {
		if (v==null) {
			v=0.0D;
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 提供精确的类型转换(Float)
	 *
	 * @param v
	 *            需要被转换的数字
	 * @return 返回转换结果
	 */
	public static float convertsToFloat(Double v) {
		if (v==null) {
			v=0.0D;
		}
		BigDecimal b = new BigDecimal(v);
		return b.floatValue();
	}

	/**
	 * 提供精确的类型转换(Int)不进行四舍五入
	 *
	 * @param v
	 *            需要被转换的数字
	 * @return 返回转换结果
	 */
	public static int convertsToInt(Double v) {
		if (v==null) {
			v=0.0D;
		}
		BigDecimal b = new BigDecimal(v);
		return b.intValue();
	}

	/**
	 * 转换成微信支付需要的字符串形式的
	 *
	 * @param v
	 *            需要被转换的数字
	 * @return 返回转换结果
	 */
	public static String convertsToWeiXin(Double v) {
		BigDecimal totalPrice  = new BigDecimal(v); //此时的单位是元
	    return totalPrice.multiply(new BigDecimal(100)).toBigInteger().toString();
	}

	/**
	 * 提供精确的类型转换(Long)
	 *
	 * @param v
	 *            需要被转换的数字
	 * @return 返回转换结果
	 */
	public static long convertsToLong(Double v) {
		if (v==null) {
			v=0.0D;
		}
		BigDecimal b = new BigDecimal(v);
		return b.longValue();
	}

	/**
	 * 返回两个数中大的一个值
	 *
	 * @param v1
	 *            需要被对比的第一个数
	 * @param v2
	 *            需要被对比的第二个数
	 * @return 返回两个数中大的一个值
	 */
	public static double returnMax(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.max(b2).doubleValue();
	}

	/**
	 * 返回两个数中小的一个值
	 *
	 * @param v1
	 *            需要被对比的第一个数
	 * @param v2
	 *            需要被对比的第二个数
	 * @return 返回两个数中小的一个值
	 */
	public static double returnMin(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.min(b2).doubleValue();
	}

	/**
	 * 精确对比两个数字
	 *
	 * @param v1
	 *            需要被对比的第一个数
	 * @param v2
	 *            需要被对比的第二个数
	 * @return 如果两个数一样则返回0，如果第一个数比第二个数大则返回1，反之返回-1
	 */
	public static int compareTo(Double v1, Double v2) {
		if (v1==null) {
			v1=0.0D;
		}
		if (v2==null) {
			v2=0.0D;
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.compareTo(b2);
	}

	/**

      　　* 将元数据前补零，补后的总长度为指定的长度，以字符串的形式返回

      　　* @param sourceDate

      　　* @param formatLength

      　　* @return 重组后的数据

      　　*/

	public static String frontCompWithZore(int sourceDate,int formatLength){
		String newString = String.format("%0"+formatLength+"d", sourceDate);
		return newString;
	}

	/**
	* @Description: 计算百分比，获得打折后的值
	* @Param: price 价格
	* @return: discount 手续费
	* @Author: lihaicheng
	* @date:2020年3月10日 上午11:14:10
	*/
	public static Double percentage(Double price, Double discount){
        BigDecimal bigDecimal = new BigDecimal(discount * 0.01);
        BigDecimal multiply = bigDecimal.multiply(new BigDecimal(price));
        return NumberUtils.sub(price, multiply.setScale(2,  BigDecimal.ROUND_DOWN).doubleValue());
    }
}